package com.wimcorp.magic.dataloader.abilities;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CellPanel;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.wimcorp.magic.data.AbilityData;
import com.wimcorp.magic.data.CostData;
import com.wimcorp.magic.dataloader.costs.CostWidget;
import com.wimcorp.magic.input.AbilityInput;
import com.wimcorp.magic.input.AbilityTriggerInput;
import com.wimcorp.magic.input.CostInput;
import com.wimcorp.magic.input.Input;
import com.wimcorp.magic.input.Target;

public class ComboAbilityWidget extends AbilityWidget {

	private ListBox inputList;
	private List<AbilityWidget> abilityWidgets;
	private Map<CostInput, CostWidget> costWidgets;
	private Grid grid;
	private VerticalPanel costPanel;

	public ComboAbilityWidget(AbilityInput ability) {
		super(ability);
		setName(ability.toString());
		abilityWidgets = new ArrayList<>();
		
	}

	protected void initAbilityFields() {
		costWidgets = new HashMap<>();
		inputList = new ListBox();
		costPanel = new VerticalPanel();
		grid = new Grid(3,2);
		addInputSingleInputOption("Input",inputList,0);
		Button addAbilitiy = new Button("Add");
		grid.setWidget(1,0,addAbilitiy);
		addAbilitiy.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				addAbilityPanel();
			}
		});
		Button removeAbilitiy = new Button("Remove");
		grid.setWidget(1,1,removeAbilitiy);
		removeAbilitiy.addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				Widget widget = getConfigurationPanel().getWidget(getConfigurationPanel().getWidgetCount() - 1);
				if (widget instanceof VerticalPanel) {
					getConfigurationPanel().remove(getConfigurationPanel().getWidgetCount() - 1);
				}
			}
		});
		initCostPanel();
		getConfigurationPanel().add(grid);
		
	}
	
	protected void addInputSingleInputOption(String label, ListBox list, int row) {
		grid.setWidget(row, 0 , new Label(label));
		for (Input input : Input.values()) {
			list.addItem(input.getName(), input.toString());
		}
		grid.setWidget(row, 1 , list);
	}
	
	private void initCostPanel() {
		grid.setWidget(2, 0, new Label("Costs"));
		costPanel.setStyleName("costPanel");
		for (final CostInput cost : CostInput.values()) {
				final VerticalPanel panel = new VerticalPanel();
				final CheckBox costCheckBox = createCheckBox(cost.toString(), cost.getName());
				panel.add(costCheckBox);
				costCheckBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
					@Override
					public void onValueChange(ValueChangeEvent<Boolean> event) {
						if (costCheckBox.getValue()) {
							// initCostFields(panel, costCheckBox);
							CostWidget costWidget = costWidgets.get(cost);
							if (costWidget == null) {
								costWidget = CostWidget.createCostWidget(cost);
								costWidgets.put(cost, costWidget);
							}
							panel.add(costWidget.getConfigurationPanel());
						} else {
							costWidgets.remove(cost);
							Widget w = panel.getWidget(0);
							panel.clear();
							panel.add(w);
						}
					}
				});

				costPanel.add(panel);
		}
		grid.setWidget(2, 1, costPanel);
	}

	private void addAbilityPanel() {
		VerticalPanel abilityPanel = new VerticalPanel();
		initAbilityPanel(abilityPanel);
		getConfigurationPanel().add(abilityPanel);
	}

	private void initAbilityPanel(CellPanel abilityPanel) {
		abilityPanel.add(new Label("Abilities"));
		abilityPanel.setStyleName("abilityPanel");
		for (final AbilityInput ability : AbilityInput.values()) {
			final VerticalPanel panel = new VerticalPanel();
			final CheckBox abilityCheckBox = createCheckBox(ability.toString(), ability.getName());
			
			panel.add(abilityCheckBox);
			abilityCheckBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
				@Override
				public void onValueChange(ValueChangeEvent<Boolean> event) {
					AbilityWidget abilityWidget = AbilityWidget.createAbilityWidget(ability);
					if (abilityCheckBox.getValue()) {
						abilityWidgets.add(abilityWidget);
						panel.add(abilityWidget.getConfigurationPanel());
					} else {
						abilityWidgets.remove(abilityWidget);
						Widget w = panel.getWidget(0);
						panel.clear();
						panel.add(w);
					}
				}
			});
			abilityPanel.add(panel);
		}
	}

	public JSONObject getAbilityConfig() {
		JSONObject config = new JSONObject();
		int i = 0;
		for (AbilityWidget abilityWidget : abilityWidgets) {
			i++;
			JSONObject ability = new JSONObject();
			ability.put("name", new JSONString(abilityWidget.getName()));
			ability.put("config", abilityWidget.getAbilityConfig());
			ability.put("abilityCosts", getCostconfig(abilityWidget.getCosts()));
			config.put("ability" + i, ability);
		}
		config.put("inputOption", getSelectedItems(inputList));
		config.put("trigger", new JSONString(AbilityTriggerInput.COMBO_TIGGER.toString()));
		return config;
	}
	
	private JSONArray getCostconfig(Set<CostData> costs) {
		JSONArray abilityCosts = new JSONArray();
		int i = 0;
		for (CostData cost : costs) {
			JSONObject conditionAbilityCost = new JSONObject();
			conditionAbilityCost.put("cost", new JSONString(cost.getCost()));
			conditionAbilityCost.put("config", (JSONObject) JSONParser.parseLenient(cost.getConfig()));
			abilityCosts.set(i, conditionAbilityCost);
			i++;
		}
		return abilityCosts;
	}

	public void load(AbilityData abilityData) {
		try {
			JSONObject config = (JSONObject) JSONParser.parseLenient(abilityData.getConfig());
			loadListBox(inputList, config.get("inputOption"));
			JSONObject ability = null;
			int i = 1;
			do {
				ability = (JSONObject) config.get("ability" + i);
				if (ability != null) {
					JSONValue name = ability.get("name");
					JSONValue abilityConfig = ability.get("config");
					AbilityInput abilityInput = AbilityInput
							.valueOf(toString(name));
					AbilityWidget checkedAbilityWidget = AbilityWidget.createAbilityWidget(abilityInput);
					Set<CostData> costs = loadCosts((JSONArray) config.get("abilityCosts"));
					checkedAbilityWidget.load(new AbilityData(abilityInput.toString(), abilityConfig.toString(),costs));
					loadAbilityPanel(checkedAbilityWidget);
				}
				i++;
			} while (ability != null);
			loadCosts(abilityData.getCosts());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private Set<CostData> loadCosts(JSONArray abilityCosts) {
		Set<CostData> costs = new HashSet<>();
		if (abilityCosts != null) {
			for (int i = 0; i < abilityCosts.size(); i++) {
				JSONObject conditionAbilityCost = (JSONObject) abilityCosts.get(i);
				costs.add(new CostData(toString(conditionAbilityCost.get("cost")), toString(conditionAbilityCost
						.get("config"))));

			}
		}
		return costs;
	}
	
	protected void loadCosts(Set<CostData> costs) {
		for (CostData cost : costs) {
			CostInput costInput = CostInput.valueOf(cost.getCost());
			CostWidget costWidget = CostWidget.createCostWidget(costInput);
			Iterator<Widget> iterator = costPanel.iterator();
			while (iterator.hasNext()) {
				Widget w = iterator.next();
				if (w instanceof CellPanel) {
					CellPanel checkBoxPanel = (CellPanel) w;
					Iterator<Widget> checkBoxPanelIterator = checkBoxPanel.iterator();
					while (checkBoxPanelIterator.hasNext()) {
						Widget checkBox = checkBoxPanelIterator.next();
						if (checkBox instanceof CheckBox) {
							if (((CheckBox) checkBox).getName().equals(cost.getCost())) {
								((CheckBox) checkBox).setValue(true);
								checkBoxPanel.add(costWidget.getConfigurationPanel());
							}
						}

					}
				}

			}
			costWidget.load(cost);
			costWidgets.put(costInput, costWidget);
		}
	}

	private void loadAbilityPanel(AbilityWidget abilityWidget) {
		VerticalPanel abilityPanel = new VerticalPanel();
		loadAbilityPanel(abilityPanel, abilityWidget);
		getConfigurationPanel().add(abilityPanel);
	}

	private void loadAbilityPanel(CellPanel abilityPanel, final AbilityWidget checkedAbilityWidget) {
		abilityPanel.add(new Label("Abilities"));
		abilityPanel.setStyleName("abilityPanel");
		for (final AbilityInput ability : AbilityInput.values()) {
			final VerticalPanel panel = new VerticalPanel();
			final CheckBox abilityCheckBox = createCheckBox(ability.toString(), ability.getName());
			if (checkedAbilityWidget.getName().equals(ability.toString())) {
				panel.add(abilityCheckBox);
				abilityCheckBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
					@Override
					public void onValueChange(ValueChangeEvent<Boolean> event) {
						if (abilityCheckBox.getValue()) {
							abilityWidgets.add(checkedAbilityWidget);
							panel.add(checkedAbilityWidget.getConfigurationPanel());
						} else {
							abilityWidgets.remove(checkedAbilityWidget);
							Widget w = panel.getWidget(0);
							panel.clear();
							panel.add(w);
						}
					}
				});
				abilityWidgets.add(checkedAbilityWidget);
				abilityCheckBox.setValue(true);
				panel.add(checkedAbilityWidget.getConfigurationPanel());
			} else {
				
				panel.add(abilityCheckBox);
				abilityCheckBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
					@Override
					public void onValueChange(ValueChangeEvent<Boolean> event) {
						final AbilityWidget abilityWidget = AbilityWidget.createAbilityWidget(ability);
						if (abilityCheckBox.getValue()) {
							abilityWidgets.add(abilityWidget);
							panel.add(abilityWidget.getConfigurationPanel());
						} else {
							abilityWidgets.remove(abilityWidget);
							Widget w = panel.getWidget(0);
							panel.clear();
							panel.add(w);
						}
					}
				});
			}
			abilityPanel.add(panel);
		}
	}
	
	public Set<CostData> getCosts() {
		Set<CostData> costs = new HashSet<>();
		for (CostWidget cost : costWidgets.values()) {
			costs.add(new CostData(cost.getName(), cost.getConfig()));
		}
		return costs;
	}

}
